#include "tape.h"
#include <stdlib.h>
#include <string.h>

Tape::Tape(void)
{
    m_size = 0;
    m_bBuffer = NULL;
    m_len = 0;
}

Tape::Tape(DWORD initSize)
{
    m_size = __max(4, initSize);
    m_bBuffer = new BYTE[m_size];
    memset(m_bBuffer, 0x00, m_size);
    m_len = 0;
}

Tape::~Tape()
{
    if(m_size != 0) {
        delete[] m_bBuffer;
    }
}

void Tape::_EnsureSize(DWORD needSize, DWORD grainSize)
{
    if(m_size < needSize) {
        DWORD extSize = ((needSize-1) / grainSize + 1) * grainSize;
        BYTE* extBuffer = new BYTE[extSize];
        memset(extBuffer, 0x00, extSize);
        if(m_size != 0) {
            if(m_len != 0) {
                memcpy(extBuffer, m_bBuffer, m_len);
            }
            delete m_bBuffer;
        }
        m_size = extSize;
        m_bBuffer = extBuffer;
    }
}

BOOL Tape::Copy(Tape* paTape)
{
    DWORD newLen = paTape->m_len;
    if (newLen > 0) {
        _EnsureSize(newLen);

        memcpy(m_bBuffer, paTape->m_bBuffer, newLen);
        m_len = newLen;
        return(TRUE);
    }
    else {
        m_len = 0;
        return(FALSE);
    }
}

BOOL Tape::Append(Tape* paTape)
{
    DWORD moreLen = paTape->m_len;
    if (moreLen > 0) {
        _EnsureSize(m_len + moreLen);

        memcpy(m_bBuffer + m_len, paTape->m_bBuffer, moreLen);
        m_len += moreLen;
        return(TRUE);
    }
    else {
        m_len = 0;
        return(FALSE);
    }
}

DWORD Tape::Export(void* pDstCache, DWORD dstSize)
{
    if((m_size == 0) || (m_len > dstSize)) {
        return(0);
    }

    if (m_len > 0) {
        memcpy(pDstCache, m_bBuffer, m_len);
    }
    return(m_len);
}

DWORD Tape::Import(const void* pSrcCache, DWORD len)
{
    if (len > 0) {
        _EnsureSize(len);

        memcpy(m_bBuffer, pSrcCache, len);
        m_len = len;
    }
    else {
        m_len = 0;
    }
    return(m_len);
}

DWORD Tape::Append(const void* pSrcCache, DWORD len)
{
    if (len > 0) {
        _EnsureSize(m_len + len);

        memcpy(m_bBuffer + m_len, pSrcCache, len);
        m_len += len;
    }
    return(m_len);
}

DWORD Tape::ImportN(const void* pSrcNcache)
{
    Ntype nt;
    memcpy(&nt, pSrcNcache, 4);
    _EnsureSize(nt.length);

    memcpy(m_bBuffer, pSrcNcache, nt.length);
    m_len = nt.length;
    return(m_len);
}

DWORD Tape::AppendN(const void* pSrcNcache)
{
    Ntype nt;
    memcpy(&nt, pSrcNcache, 4);
    _EnsureSize(m_len + nt.length);

    memcpy(m_bBuffer + m_len, pSrcNcache, nt.length);
    m_len += nt.length;
    return(m_len);
}
